package com.heyqing.prepare.bitwise;

import com.heyqing.prepare.Tools;

import java.util.HashMap;
import java.util.Map;

/**
 * ClassName:BitwiseOperation
 * Package:com.heyqing.prepare.bitwise
 * Description:
 * <p>
 * 位运算题解
 *
 * @Date:2024/7/21
 * @Author:Heyqing
 */
public class BitwiseOperation {

    /**
     * 判断奇偶数-与
     * <p>
     * return true is odd
     *
     * @param number
     * @return
     */
    public static Boolean OddOrEven(int number) {
        return (number & 1) == 1;
    }

    /**
     * 找到落单的数-异或
     * <p>
     * return target number
     *
     * @param targetArray
     * @return
     */
    public static Integer findSingularNumber(int[] targetArray) {
        int targetNumber = 0;
        for (int num : targetArray) {
            targetNumber ^= num;
        }
        return targetNumber;
    }

    /**
     * 找出成双的数-异或
     * <p>
     * return target number
     *
     * @param targetArray
     * @return
     */
    public static Integer findPairNumberByXOR(int[] targetArray) {
        int targetNumber = 0;
        for (int num : targetArray) {
            if ((targetNumber ^ num) == 0) {
                break;
            }
            targetNumber = num;
        }
        return targetNumber;
    }

    /**
     * 找出成双的数-辅助空间
     * <p>
     * return target number
     *
     * @param targetArray
     * @return
     */
    public static Integer findPairNumberByHelperSpace(int[] targetArray) {
        int targetNumber = 0;
        //辅助空间，1、辅助空间的下标为目标数组的值，辅助空间对应下标的值为目标数组值出现的次数，缺点为目标数组中的值范围不确定
        //这里假设我就假设目标数组中元素最大不超过999，当然你可以使用List
        int[] helperArray = new int[999];
        for (int num : targetArray) {
            helperArray[num]++;
            //如果辅助数组值为2说明此下标出现了两次
            if (helperArray[num] == 2) {
                targetNumber = num;
                String info = "找出成双的数-辅助空间-数组：" + targetNumber;
                Tools.func(info);
                break;
            }
        }
        //辅助空间，2、使用map，key为目标数组的值，如果同一个key出现储存两次两次的情况，则此数值为成双数值
        targetNumber = 0;
        Map<Integer, Integer> helperMap = new HashMap<>();
        for (int num : targetArray) {
            boolean isExist = helperMap.containsKey(num);
            if (isExist) {
                //如果存在，则说明此数在此数组出现第二次
                targetNumber = num;
                String info = "找出成双的数-辅助空间-Map：" + targetNumber;
                Tools.func(info);
                break;
            } else {
                helperMap.put(num, 1);
            }
        }
        return targetNumber;
    }

    /**
     * 二进制数中1的个数-移动数字
     * <p>
     * return counts
     *
     * @param number
     * @return
     */
    public static Integer findBinary1CountsByMoveNumber(int number) {
        int counts = 0;
        //因为int为4byte即2^32，故须循环32次
        for (int i = 0; i < 32; i++) {
            if (((number >> i) & 1) == 1) {
                counts++;
            }
        }
        return counts;
    }

    /**
     * 二进制数中1的个数-移动1
     * <p>
     * return counts
     *
     * @param number
     * @return
     */
    public static Integer findBinary1CountsByMove1(int number) {
        int counts = 0;
        //因为int为4byte即2^32，故须循环32次
        for (int i = 0; i < 32; i++) {
            if ((number & (1 << i)) == (1 << i)) {
                counts++;
            }
        }
        return counts;
    }

    /**
     * 二进制数中1的个数-减1
     * <p>
     * return counts
     *
     * @param number
     * @return
     */
    public static Integer findBinary1CountsBySubtraction1(int number) {
        int counts = 0;
        while (number != 0) {
            counts++;
            number &= (number - 1);
        }
        return counts;
    }

    /**
     * 2的整数幂
     *
     * @param number
     * @return
     */
    public static Boolean isPowerOf2(int number) {
        //选用 二进制数中1的个数 方法之一
        //二进制数中1的个数为1的为2的整数幂
        return (number & (number - 1)) == 0;
    }

    /**
     * 奇偶位互换
     *
     * @param number
     * @return
     */
    public static Integer OddAndEvenSwap(int number) {
        int even = 0xaaaaaaaa;
        int odd = 0x55555555;
        return ((number&even)>>1)^((number&odd)<<1);
    }
}
